package com.aaa.sbm.configuration;

import com.aaa.sbm.util.ConstantUtil;
import com.aaa.sbm.util.MyCustomRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @FileName: SpringShiroConfig
 * @Description:  spring整合shiro配置  相当于spring-shiro-config.xml文件
 * @Author: zhz
 * @CreateTime: 2024/4/9 14:47
 * @Version: 1.0.0
 */
@Configuration // <beans></beans>
public class SpringShiroConfig {

    /**
     * 配置ShiroFilterFactoryBean
     *   shiro过滤工厂 拦截所有请求，根据配置做不同处理，并且要注入SecurityManager等
     * @return
     */
    @Bean  //<bean id='shiroFilter' class='org.apache.shiro.spring.web.ShiroFilterFactoryBean'>
    public ShiroFilterFactoryBean shiroFilter(){
        //实例化
        ShiroFilterFactoryBean shiroFilterFactoryBean =
                new ShiroFilterFactoryBean();
        //set注入
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        //设置未认证（没有登录）跳转的登录页面
        shiroFilterFactoryBean.setLoginUrl("/html/login.html");
        //登录成功后跳转页面 （有bug 不起作用）
        //shiroFilterFactoryBean.setSuccessUrl("/html/index.html");
        //设置未授权页面（访问了不该访问的资源，跳转的错误提示页面）
        shiroFilterFactoryBean.setUnauthorizedUrl("/html/unauthorized.html");

        //定义Map  使用LinkedHashMap 按照放入顺序排序
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //   /dept/** = authc, roles[guanliyuan]    访问路径中含有dept  authc必须认证（登录） roles[guanliyuan] 并且具备guanliyuan角色才可以访问
        //   /docs/** = authc, perms[document:read]   访问路径中含有docs  authc必须认证（登录） perms[document:read] 并且具备document:read权限才可以访问
        //   /** = authc     **统配所有路径  authc  必须认证（登录）才能访问
        //key 是访问的路径   value  是权限
        //anon就是要放开的资源
        filterChainDefinitionMap.put("/html/login.html","anon");  //anon= anonymous 可以不登录访问
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/images/**","anon");
        filterChainDefinitionMap.put("/user/login","anon");
        //用户退出
        filterChainDefinitionMap.put("/user/logout/a/b/c","logout");
        //必须登录才能访问的资源  这个必须放下面
        filterChainDefinitionMap.put("/**","authc");
        //设置过滤链定义
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return   shiroFilterFactoryBean;
    }

    /**
     * 配置SecurityManager
     * SecurityManager  是shiro 所有Subject的幕后主使，是核心。。。
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager(){
        //实例化
        DefaultWebSecurityManager defaultWebSecurityManager =
                new DefaultWebSecurityManager();
        //set注入realm
        defaultWebSecurityManager.setRealm(myRealm());
        return defaultWebSecurityManager;
    }

    /**
     * 配置Realm
     *  安全数据的桥梁
     * @return
     */
    @Bean
    public MyCustomRealm myRealm(){
        //实例化
        MyCustomRealm myCustomRealm = new MyCustomRealm();
        //set注入
        myCustomRealm.setCredentialsMatcher(credentialsMatcher());
     return myCustomRealm;
    }


    /**
     * 配置CredentialsMatcher
     *    HashedCredentialsMatcher：密码加密算法类
     * @return
     */
    @Bean
    public HashedCredentialsMatcher  credentialsMatcher(){
        //实例化
        HashedCredentialsMatcher hashedCredentialsMatcher =
                new HashedCredentialsMatcher();
         //设置算法名称
        hashedCredentialsMatcher.setHashAlgorithmName(ConstantUtil.ShiroCredentialsMatcher.HASH_ALGORITHM_NAME);
        //设置hash次数
        hashedCredentialsMatcher.setHashIterations(ConstantUtil.ShiroCredentialsMatcher.HASH_ITERATIONS);
        return hashedCredentialsMatcher;
    }

    /**
     * 实例自动代理创建器   开启Aop前置通知，在后面配置识别方法权限过滤方法之前做处理
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator  defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =new DefaultAdvisorAutoProxyCreator();
        //让没有接口的Controller可以使用代理
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    /**
     * 开启shiro权限过滤注解功能，让Controller中的资源支持@RequiresRoles()    @RequiresPermissions()
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;

    }

    /**
     * 解决shiroFilterFactoryBean.setUnauthorizedUrl配置不启用的问题
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver resolver() {
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.setProperty("org.apache.shiro.authz.UnauthorizedException",
                "/html/unauthorized.html");
        resolver.setExceptionMappings(properties);
        return resolver;
    }
}
